<template>
  <div class="lowcode-plugin-sample-preview">
    <Suspense>
      <template #default>
        <VueRenderer
          v-if="schema"
          class="lowcode-plugin-sample-preview-content"
          :schema="schema"
          :components="components"
          :appHelper="appHelper"
        />
      </template>
      <template #fallback>
        <div class="lowcode-plugin-sample-preview-loading">加载中...</div>
      </template>
    </Suspense>
  </div>
</template>

<script setup>
import { ref, onMounted, toRaw, defineEmits } from 'vue'
import VueRenderer from '@knxcloud/lowcode-vue-renderer'
import { buildComponents, AssetLoader } from '@knxcloud/lowcode-utils'
import * as ElementPlus from 'element-plus'
import axios from 'axios'
import schemaData from '../assets/schema.json'
import assetsData from '../assets/assets.json'

// 定义事件
const emit = defineEmits(['on-error', 'on-loaded'])

// 声明响应式变量
const schema = ref(null)
const components = ref({})

// 创建appHelper对象，提供mock数据和工具函数
const appHelper = {
  utils: {
    request: async (config) => {
      console.log('请求拦截:', config)
      if (config.url) {
        console.log('返回mock数据')
        return {
          data: {
            code: 0,
            data: {
              info: 'Hello LowCode Engine',
              user: {
                username: 'admin',
                password: 'password'
              }
            },
            msg: 'success'
          }
        }
      }
      return axios(config)
    },
    formatDate: (date) => new Date(date).toLocaleString(),
    handleError: (err) => {
      console.warn('请求错误:', err)
      emit('on-error', err)
      return {
        code: 0,
        data: {
          info: '错误后的默认数据',
          user: {
            username: 'guest',
            password: ''
          }
        },
        msg: 'error'
      }
    },
    onSubmit: (ev) => {
      console.log('表单提交:', ev)
      ev.preventDefault()
      // 模拟提交
      console.log('提交数据:', schema.value.state?.info?.user)
      return false
    }
  }
}

// 创建ElementPlus到NaiveUI的组件映射
const createComponentMap = () => {
  // 基础组件映射
  return {
    NCard: {
      component: ElementPlus.ElCard,
      props: (props) => {
        return {
          header: props.title,
          shadow: props.bordered ? 'always' : 'never',
          ...props
        }
      }
    },
    NForm: {
      component: ElementPlus.ElForm,
      props: (props) => {
        return {
          model: props.model,
          labelWidth: props['label-width'],
          labelPosition: props['label-placement'] === 'top' ? 'top' : 'right',
          ...props
        }
      }
    },
    NFormItem: {
      component: ElementPlus.ElFormItem,
      props: (props) => {
        return {
          label: props.label,
          prop: props.path,
          rules: props.rule ? [props.rule] : undefined,
          ...props
        }
      }
    },
    NInput: {
      component: ElementPlus.ElInput,
      props: (props) => {
        return {
          modelValue: props['v-model:value'],
          placeholder: props.placeholder,
          type: props.type || 'text',
          showPassword: props.type === 'password',
          ...props
        }
      }
    },
    NButton: {
      component: ElementPlus.ElButton,
      props: (props) => {
        return {
          type:
            props.type === 'primary'
              ? 'primary'
              : props.type === 'success'
                ? 'success'
                : props.type === 'warning'
                  ? 'warning'
                  : props.type === 'error'
                    ? 'danger'
                    : 'default',
          size: props.size === 'small' ? 'small' : props.size === 'large' ? 'large' : 'default',
          ...props
        }
      }
    },
    NText: {
      component: 'span',
      props: (props) => props
    },
    NSpace: {
      component: ElementPlus.ElSpace,
      props: (props) => {
        return {
          direction: props.vertical ? 'vertical' : 'horizontal',
          alignment: props.align,
          size: props.size === 'small' ? 'small' : props.size === 'large' ? 'large' : 'default',
          ...props
        }
      }
    },
    NAvatar: {
      component: ElementPlus.ElAvatar,
      props: (props) => {
        return {
          src: props.src,
          size: props.size === 'small' ? 'small' : props.size === 'large' ? 'large' : 'default',
          shape: props.circle ? 'circle' : 'square',
          ...props
        }
      }
    },
    NGrid: {
      component: ElementPlus.ElRow,
      props: (props) => {
        return {
          gutter: props['x-gap'] || 0,
          ...props
        }
      }
    },
    NGridItem: {
      component: ElementPlus.ElCol,
      props: (props) => {
        return {
          span: props.span,
          offset: props.offset,
          ...props
        }
      }
    }
  }
}

// 初始化函数
const init = async () => {
  try {
    console.log('初始化渲染器...')

    // 拦截全局fetch请求
    const originalFetch = window.fetch
    window.fetch = function (url, options) {
      console.log('fetch请求拦截:', url)
      if (url) {
        console.log('返回mock数据(fetch)')
        return Promise.resolve({
          ok: true,
          status: 200,
          json: () =>
            Promise.resolve({
              info: 'Hello LowCode Engine',
              user: {
                username: 'admin9999999',
                password: 'password'
              }
            })
        })
      }
      return originalFetch(url, options)
    }

    // 1. 从assets.json中获取组件信息
    const { packages = [], components: componentsInfo = [] } = assetsData

    // 2. 构建componentsMap
    const componentsMap = {}
    componentsInfo.forEach((component) => {
      componentsMap[component.componentName] = component
    })

    // 3. 构建libraryMap和libraryAsset
    const libraryMap = {}
    const libraryAsset = []
    packages.forEach(({ package: _package, library, urls, renderUrls }) => {
      libraryMap[_package] = library
      if (renderUrls) {
        libraryAsset.push(renderUrls)
      } else if (urls) {
        libraryAsset.push(urls)
      }
    })

    // 4. 添加ElementPlus作为NaiveUI的替代
    libraryMap['naive-ui'] = 'ElementPlus'

    // 5. 设置全局变量
    window.ElementPlus = ElementPlus

    // 6. 加载资源
    console.log('加载资源...')
    await new AssetLoader().load(libraryAsset)
    console.log('资源加载成功')

    // 7. 构建组件
    console.log('构建组件...')
    const builtComponents = await buildComponents(libraryMap, componentsMap)

    // 8. 添加组件映射
    const componentMap = createComponentMap()
    Object.keys(componentMap).forEach((key) => {
      if (builtComponents[key]) {
        const { component, props: propsTransformer } = componentMap[key]
        const originalRender = builtComponents[key].render

        if (originalRender) {
          builtComponents[key].render = function (props, ...args) {
            const transformedProps = propsTransformer ? propsTransformer(props) : props
            return originalRender.call(this, transformedProps, ...args)
          }
        } else {
          builtComponents[key] = component
        }
      } else {
        builtComponents[key] = componentMap[key].component
      }
    })

    components.value = toRaw(builtComponents)
    console.log('组件构建完成:', Object.keys(components.value))

    // 9. 设置schema
    schema.value = toRaw(schemaData)
    console.log('Schema设置完成')

    // 10. 通知加载完成
    emit('on-loaded')
  } catch (error) {
    console.error('初始化失败:', error)
    emit('on-error', error)
  }
}

// 刷新方法
const refresh = async () => {
  schema.value = null
  components.value = {}
  await init()
}

// 暴露方法
defineExpose({
  refresh
})

// 组件挂载时初始化
onMounted(() => {
  init()
})
</script>

<style scoped>
.lowcode-plugin-sample-preview {
  width: 100%;
  height: 100%;
  min-height: 400px;
  position: relative;
}

.lowcode-plugin-sample-preview-content {
  width: 100%;
  height: 100%;
}

.lowcode-plugin-sample-preview-loading {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  min-height: 200px;
  font-size: 16px;
  color: #666;
}
</style>
